// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

#pragma once

#include <nebula/core/array.h>
#include <nebula/core/extension_type.h>
#include <nebula/core/visitor_generate.h>

namespace nebula {

#define ARRAY_VISIT_INLINE(TYPE_CLASS)                                                   \
      case TYPE_CLASS##Type::type_id:                                                        \
        return visitor->Visit(                                                               \
            turbo::checked_cast<const typename TypeTraits<TYPE_CLASS##Type>::ArrayType&>( \
                array),                                                                      \
            std::forward<ARGS>(args)...);

    /// \brief Apply the visitors Visit() method specialized to the array type
    ///
    /// \tparam VISITOR Visitor type that implements Visit() for all array types.
    /// \tparam ARGS Additional arguments, if any, will be passed to the Visit function after
    /// the `arr` argument
    /// \return turbo::Status
    ///
    /// A visitor is a type that implements specialized logic for each Nebula type.
    /// Example usage:
    ///
    /// ```
    /// class ExampleVisitor {
    ///   turbo::Status Visit(nebula::NumericArray<Int32Type> arr) { ... }
    ///   turbo::Status Visit(nebula::NumericArray<Int64Type> arr) { ... }
    ///   ...
    /// }
    /// ExampleVisitor visitor;
    /// visit_array_inline(some_array, &visitor);
    /// ```
    template<typename VISITOR, typename... ARGS>
    inline turbo::Status visit_array_inline(const Array &array, VISITOR *visitor, ARGS &&... args) {
        switch (array.type_id()) {
            NEBULA_GENERATE_FOR_ALL_TYPES(ARRAY_VISIT_INLINE);
            default:
                break;
        }
        return turbo::unimplemented_error("Type not implemented");
    }

#undef ARRAY_VISIT_INLINE

}  // namespace nebula
